#include "SqlField.h"


namespace sql
{

const char *Field::id = "_ID";

Field::Field(field_use use)
{
    this->_name.clear();
    this->_use = use;
    this->_type = type_undefined;
    this->_index = -1;
    this->_flags = flag_none;

    if ((FIELD_KEY == use) ||
            (FIELD_KEY_AUTOINCREMENT == use))
    {
        this->_name = id;
        this->_type = type_int;
        this->_flags = flag_primary_key;

        if (FIELD_KEY_AUTOINCREMENT == use)
        {
            this->_flags |= flag_autoincrement;
        }
    }
}

Field::Field(string name, field_type type, int flags)
{
    this->_name = name;
    this->_use = FIELD_DEFAULT;
    this->_type = type;
    this->_index = -1;
    this->_flags = flags;
}

Field::Field(const Field& value)
{
    _name = value._name;
    _use = value._use;
    _type = value._type;
    _index = value._index;
    _flags = value._flags;
    _references = value._references;
}

bool Field::isKeyIdField() const
{
    return (_use == FIELD_KEY);
}

bool Field::isEndingField() const
{
    return (_use == DEFINITION_END);
}

field_type Field::getType() const
{
    return _type;
}

int Field::getIndex() const
{
    return _index;
}

string Field::getName() const
{
    return _name;
}

string Field::getTypeStr() const
{
    switch (_type)
    {
    case type_int:
        return "INTEGER";

    case type_text:
        return "TEXT";

    case type_float:
        return "REAL";

    case type_bool:
        return "INTEGER";

    case type_time:
        return "INTEGER";

    case type_undefined:
        break;
    }

    return "";
}

bool Field::isPrimaryKey() const
{
    return ((_flags & flag_primary_key) == flag_primary_key);
}

bool Field::isAutoincrement() const
{
    return ((_flags & flag_autoincrement) == flag_autoincrement);
}

bool Field::isNotNull() const
{
    return ((_flags & flag_not_null) == flag_not_null);
}

bool Field::isUnique() const
{
    return ((_flags & flag_unique) == flag_unique);
}

bool Field::isIgnored() const
{
    return ((_flags & flag_ignored) == flag_ignored);
}


string Field::getDefinition() const
{
    string value = _name + " " + getTypeStr();

    if (isPrimaryKey())
    {
        value += " PRIMARY KEY";
    }

    if (isAutoincrement())
    {
        value += " AUTOINCREMENT";
    }

    if (isUnique())
    {
        value += " UNIQUE";
    }

    if (isNotNull())
    {
        value += " NOT NULL";
    }

    value += " " + _references;

    return trim(value);
}

void Field::setReferences(string refer)
{
    std::string::size_type pos = refer.find("REFERENCES");

    if (pos == std::string::npos)
    {
        pos = refer.find("references");
    }

    _references.assign(refer, pos, std::string::npos);
}

Field* Field::createFromDefinition(string value)
{
    std::vector<string> vec;

    listToVector(value, vec, " ");

    const int count = (int)vec.size();

    string _name;
    string _references = "";

    field_use _use = FIELD_DEFAULT;
    field_type _type = type_undefined;

    int _flags = flag_none;

    //parse name
    if (count > 0)
    {
        _name = vec[0];
    }

    //parse type
    if (value.find("TEXT") != std::string::npos ||
            value.find("text") != std::string::npos)
    {
        _type = type_text;
    }

    if (value.find("INTEGER") != std::string::npos ||
            value.find("interger") != std::string::npos)
    {
        _type = type_int;
    }

    if (value.find("REAL") != std::string::npos ||
            value.find("real") != std::string::npos)
    {
        _type = type_float;
    }

    //parse optional flags
    if (value.find("PRIMARY KEY") != std::string::npos ||
            value.find("primary key") != std::string::npos)
    {
        _use = FIELD_KEY;
        _flags |= flag_primary_key;
    }

    if (value.find("AUTOINCREMENT") != std::string::npos ||
            value.find("autoincrement") != std::string::npos )
    {
        _use = FIELD_KEY_AUTOINCREMENT;
        _flags |= flag_autoincrement;
    }

    if (value.find("NOT NULL") != std::string::npos ||
            value.find("not null") != std::string::npos)
    {
        _flags |= flag_not_null;
    }

    if (value.find("UNIQUE") != std::string::npos ||
            value.find("unique") != std::string::npos)
    {
        _flags |= flag_unique;
    }

    //parse references
    std::string::size_type pos = value.find("REFERENCES");

    if (pos == std::string::npos)
    {
        pos = value.find("references");
    }

    _references.assign(value, pos, std::string::npos);

#if 0

    //parse type
    if (count > 1)
    {
        std::string& type = vec[1];
#if 0

        if (type.compare("INTEGER") == 0)
        {
            _type = type_int;
        }

        if (type.compare("TEXT") == 0)
        {
            _type = type_text;
        }

        if (type.compare("REAL") == 0)
        {
            _type = type_float;
        }

#endif

        if (0 == stricmp(type.c_str(), "interger"))
        {
            _type = type_int;
        }

        if (0 == stricmp(type.c_str(), "text"))
        {
            _type = type_text;
        }

        if (0 == stricmp(type.c_str(), "real"))
        {
            _type = type_float;
        }
    }

    //parse optional flags
    if (count > 2)
    {
        std::string flags = vec[2];

        if (count > 3)
        {
            flags += " " + vec[3];
        }

        if (flags.find("PRIMARY KEY") != std::string::npos ||
                flags.find("primary key") != std::string::npos)
        {
            _use = FIELD_KEY;
            _flags |= flag_primary_key;
        }

        if (flags.find("NOT NULL") != std::string::npos ||
                flags.find("not null") != std::string::npos)
        {
            _flags |= flag_not_null;
        }

        if (flag_none == _flags)
        {
            if (flags.find("REFERENCES") != std::string::npos ||
                    flags.find("references") != std::string::npos)
            {
                _references = flags;

                for (int i = 4; i < count; i++)
                {
                    _references += " " + vec[i];
                }
            }
        }
        else
        {
            if (count > 4)
            {
                string references = vec[4];

                if (0 == stricmp(references.c_str(), "references"))
                {
                    for (int i = 5; i < count; i++)
                    {
                        references += " " + vec[i];
                    }

                    _references = references;
                }
            }
        }
    }

#endif

    Field* field = NULL;

    if (!_name.empty())
    {
        if (_type != type_undefined)
        {
            if (_use == FIELD_DEFAULT)
            {
                field = new Field(_name, _type, _flags);
                field->setReferences(_references);
            }
            else
            {
                field = new Field(_use);
            }
        }
    }

    return field;
}

void Field::setIgnored(bool ignored)
{
    if (ignored)
    {
        _flags = _flags | flag_ignored;
        return;
    }

    _flags = _flags & (~(static_cast<decltype(_flags)>(flag_ignored)));
}

//sql eof
};
